package com.duojuhe.common.utils.dateutils;

import com.duojuhe.common.constant.SingleStringConstant;
import com.duojuhe.common.exception.base.DuoJuHeException;
import com.duojuhe.common.result.ErrorCodes;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 日期操作工具类
 *
 * @date 2018/5/30.
 */
@Slf4j
public class DateUtils {
    private static final String FIRST_SECOND = "00:00:00";
    private static final String LAST_SECOND = "23:59:59";
    public static final String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String yyyy = "yyyy";
    public static final String MM = "MM";
    public static final String yyyy_MM = "yyyy-MM";
    public static final String yyyyMMdd = "yyyyMMdd";
    public static final String yyyy_MM_ddHHmm = "yyyy-MM-dd HH:mm";
    public static final String dd = "dd";
    public static final String yyyyMMddHHmmss = "yyyyMMddHHmmss";
    public static final String yyyy_MM_ddHHmmssSSS = "yyyy-MM-dd HH:mm:ss SSS";


    /**
     * date按照指定格式转换
     * @param date
     * @param pattern
     * @return
     */
    public static String dateToString(Date date, String pattern) {
        if (date != null && StringUtils.isNotEmpty(pattern)) {
            SimpleDateFormat format = new SimpleDateFormat(pattern);
            return format.format(date);
        } else {
            return "";
        }
    }


    /**
     * 获取开始日期
     * @return
     */
    public static String getStartDateTime(String startDate){
        try {
            String date = "";
            if (StringUtils.isNotBlank(startDate)){
                date = dateToString(stringToDate(startDate,DEFAULT_DATE_FORMAT),DEFAULT_DATETIME_FORMAT);
            }
            return date;
        }catch (Exception e){
            return "";
        }
    }

    /**
     * yyyy-MM-dd 转换成 yyyy-MM-dd HH:mm:ss 格式转换时间为最后一秒
     */
    public static Date toLastSecond(@NonNull Date date) {
        try {
            return parseDateTime(dateToString(date,DEFAULT_DATE_FORMAT) + SingleStringConstant.ONE_SPACE + LAST_SECOND);
        } catch (Exception ignored) {
            return null;
        }
    }

    /**
     * 格式化时间
     *
     * @param date
     * @return
     */
    public static String dateToString(Date date) {
        if (date != null) {
            SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATETIME_FORMAT);
            return format.format(date);
        } else {
            return "";
        }
    }



    /**
     * 计算两个日期之间相差的分钟数
     *
     * @param startDate 较小的时间
     * @param endDate   较大的时间
     * @return 相差分钟
     */
    public static Long differenceMinute(Date startDate, Date endDate) {
        try {
            return  (endDate.getTime()-startDate.getTime())/1000/60;
        } catch (Exception e) {
            return 0L;
        }
    }

    /**
     * 计算两个时间差
     */
    public static String getDatePoor(Date endDate, Date startDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - startDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }


    /**
     * 获取 yyyy-MM 开始日期 -> yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static String getStartDateTimeOf_yyyy_MM(String startDate){
        try {
            String date = "";
            if (StringUtils.isNotBlank(startDate)){
                date = dateToString(stringToDate(startDate,yyyy_MM),DEFAULT_DATETIME_FORMAT);
            }
            return date;
        }catch (Exception e){
            return "";
        }
    }


    /**
     * 获取 yyyy-MM 结束日期 -> yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static String getEndDateTimeOf_yyyy_MM(String endDate){
        try {
            String date = "";
            if (StringUtils.isNotBlank(endDate)){
                Calendar origin = Calendar.getInstance();
                origin.setTime(stringToDate(endDate,yyyy_MM));
                int lastDay = origin.getActualMaximum(Calendar.DATE);
                origin.set(Calendar.DAY_OF_MONTH, lastDay);
                origin.set(Calendar.HOUR, 23);
                origin.set(Calendar.MINUTE, 59);
                origin.set(Calendar.SECOND, 59);
                date = dateToString(origin.getTime(),DEFAULT_DATETIME_FORMAT);
            }
            return date;
        }catch (Exception e){
            return "";
        }
    }

    /**
     * 计算两个日期之间的所有天
     *
     * @param minDate
     * @param maxDate
     * @return
     */
    public static List<String> getDaysBetween(Date minDate, Date maxDate) {
        ArrayList<String> result = new ArrayList<String>();
        if (minDate==null || maxDate==null){
            return result;
        }
        try {
            long startTime = minDate.getTime();
            long endTime = maxDate.getTime();
            long oneDay = 1000 * 60 * 60 * 24L;
            long time = startTime;
            while (time <= endTime) {
                Date d = new Date(time);
                result.add(dateToString(d,DEFAULT_DATE_FORMAT));
                time += oneDay;
            }
            return result;
        } catch (Exception e) {
            return result;
        }
    }


    /**
     * 根据出生日期计算年龄
     * @param birthDay
     * @return
     */
    public static String getAgeByBirthDay(Date birthDay) {
        try {
            if (birthDay == null){
                return "--";
            }
            Calendar cal = Calendar.getInstance();
            if (cal.before(birthDay)) { //出生日期晚于当前时间，无法计算
                return "--";
            }
            int yearNow = cal.get(Calendar.YEAR);  //当前年份
            int monthNow = cal.get(Calendar.MONTH);  //当前月份
            int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH); //当前日期
            cal.setTime(birthDay);
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
            int age = yearNow - yearBirth;   //计算整岁数
            if (monthNow <= monthBirth) {
                if (monthNow == monthBirth) {
                    if (dayOfMonthNow < dayOfMonthBirth) age--;
                } else {
                    age--;//当前月份在生日之前，年龄减一
                }
            }
            return String.valueOf(age);
        }catch (Exception e){
            return "--";
        }
    }

    /**
     * 判断时间是不是今天
     *
     * @param date
     * @return 是返回true，不是返回false
     */
    public static boolean isToday(Date date) {
        try {
            if (date==null){
                return false;
            }
            //当前时间
            Date now = new Date();
            SimpleDateFormat sf = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
            //获取今天的日期
            String nowDay = sf.format(now);
            //对比的时间
            String day = sf.format(date);
            return day.equals(nowDay);
        }catch (Exception e){
            return false;
        }
    }



    /**
     * 获取结束日期
     * @return
     */
    public static String getEndDateTime(String endDate){
        try {
            String date = "";
            if (StringUtils.isNotBlank(endDate)){
                Calendar origin = Calendar.getInstance();
                origin.setTime(stringToDate(endDate,DEFAULT_DATE_FORMAT));
                origin.set(Calendar.HOUR, 23);
                origin.set(Calendar.MINUTE, 59);
                origin.set(Calendar.SECOND, 59);
                date = dateToString(origin.getTime(),DEFAULT_DATETIME_FORMAT);
            }
            return date;
        }catch (Exception e){
            return "";
        }
    }

    /**
     * 给传过来的时间加指定天数在返回
     *
     * @param dateString
     * @param pattern
     * @return
     */
    public static String dateToString(String dateString, int pattern) {
        try {
            if (StringUtils.isNotBlank(dateString)) {
                SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
                Date date = dateAdd(format.parse(dateString), pattern);
                return format.format(date);
            } else {
                return "";
            }
        } catch (Exception var4) {
            return "";
        }
    }


    /**
     * 以循环的方式计算日期
     * @param beginDate endDate
     * @param
     * @return
     */
    public static List<Date> getEveryday(Date beginDate , Date endDate){
        long startTime = beginDate.getTime();
        long endTime = endDate.getTime();
        long oneDay = 1000 * 60 * 60 * 24L;
        long time = startTime;
        List<Date> everyDays = new ArrayList<Date>();
        while (time <= endTime) {
            Date d = new Date(time);
            everyDays.add(d);
            time += oneDay;
        }
        return everyDays;
    }



    /**
     * 月加减月数
     *
     * @param date
     * @param n
     * @return
     */
    public static Date monthAdd(Date date, int n) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, n);
        return calendar.getTime();
    }

    /**
     * 日期加减天数
     *
     * @param date
     * @param n
     * @return
     */
    public static Date dateAdd(Date date, int n) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_YEAR, n);
        return calendar.getTime();
    }



    /**
     * 日期加减分钟
     *
     * @param date
     * @param n
     * @return
     */
    public static Date dateMinute(Date date, int n) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, n);
        return calendar.getTime();
    }


    /**
     * 日期秒数加
     *
     * @param second
     * @return
     */
    public static Date dateAddSecond(int second) {
        Calendar calendar = Calendar.getInstance();//获得当前时间
        calendar.add(Calendar.SECOND, second);
        return calendar.getTime();
    }

    /**
     * 检查日期是否在指定分钟之内
     * @param dateTime
     */
    public static boolean checkDateTimeWithinMinutes(Date dateTime,Integer minute) {
        Calendar c1=Calendar.getInstance();
        Calendar c2=Calendar.getInstance();
        Calendar c3=Calendar.getInstance();
        c1.setTime(dateTime);//要判断的日期
        c2.setTime(new Date());//初始日期
        c3.setTime(new Date());//也给初始日期 把分钟加2
        c3.add(Calendar.MINUTE, minute);
        c2.add(Calendar.MINUTE,-minute);//减去2分钟
        return c1.after(c2) && c1.before(c3);
    }

    /**
     * 日期字符串格式转成指定格式时间
     *
     * @param str
     * @param pattern
     * @return
     * @throws
     */
    public static Date stringToDate(String str, String pattern) throws DuoJuHeException {
        if (!StringUtils.isEmpty(str) && !StringUtils.isEmpty(pattern)) {
            SimpleDateFormat format = new SimpleDateFormat(pattern);
            try {
                format.setTimeZone(TimeZone.getTimeZone("GMT+8"));
                return format.parse(str);
            } catch (Exception var4) {
                log.warn("String 转换成 Date 参数格式不正确, str:{}, pattern:{}", str, pattern);
                throw new DuoJuHeException(ErrorCodes.PARAM_ERROR);
            }
        } else {
            throw new DuoJuHeException(ErrorCodes.PARAM_ERROR);
        }
    }


    /**
     * 日期字符串格式转成指定格式时间
     */
    public static Date parseDate(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
        try {
            format.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            return format.parse(str);
        } catch (Exception ignored) {
        }
        return null;
    }

    /**
     * 日期字符串格式转成指定格式时间
     */
    public static Date parseDate(String str, String pattern) {
        if (StringUtils.isEmpty(str) || StringUtils.isEmpty(pattern)) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        try {
            format.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            return format.parse(str);
        } catch (Exception ignored) {
        }
        return null;
    }

    /**
     * 日期字符串格式转成指定格式时间
     */
    public static Date parseDateTime(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATETIME_FORMAT);
        try {
            format.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            return format.parse(str);
        } catch (Exception ignored) {
        }
        return null;
    }


    /**
     * 计算两个日期之间相差的天数
     *
     * @param startDate 较小的时间
     * @param endDate   较大的时间
     * @return 相差天数
     */
    public static int daysBetween(Date startDate, Date endDate) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
            startDate = sdf.parse(sdf.format(startDate));
            endDate = sdf.parse(sdf.format(endDate));
            Calendar cal = Calendar.getInstance();
            cal.setTime(startDate);
            long time1 = cal.getTimeInMillis();
            cal.setTime(endDate);
            long time2 = cal.getTimeInMillis();
            long between_days = (time2 - time1) / (1000 * 3600 * 24);
            int days = Integer.parseInt(String.valueOf(between_days));
            return Math.max(days, 0);
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 两个时间比较大小
     *
     * @param startDate 较小的时间
     * @param endDate   较大的时间
     * @return 相差天数
     */
    public static boolean compareDate(Date startDate, Date endDate) {
        return startDate.getTime()<endDate.getTime();
    }

    /**
     * 获取指定日期月份的最后一天
     * @param date
     * @return
     */
    public static Date getLastDayOfMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 获取某月最大天数
        int lastDay = cal.getActualMaximum(Calendar.DATE);
        // 设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, lastDay);
        // 格式化日期
        return cal.getTime();
    }

    /**
     * 计算两个日期之间的所有月份
     * @param minDate
     * @param maxDate
     * @return
     */
    public static List<String> getMonthBetween(String minDate, String maxDate)  {
        ArrayList<String> result = new ArrayList<String>();
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(yyyy_MM);//格式化为年月
            Calendar min = Calendar.getInstance();
            Calendar max = Calendar.getInstance();
            min.setTime(sdf.parse(minDate));
            min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);
            max.setTime(sdf.parse(maxDate));
            max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);
            Calendar curr = min;
            while (curr.before(max)) {
                result.add(sdf.format(curr.getTime()));
                curr.add(Calendar.MONTH, 1);
            }
            min = null;max = null;curr = null;
            return result;
        }catch (Exception e){
            return result;
        }
    }

    /**
     * 获取某个日期月份天数
     * @param date
     * @return
     */
    public static int getDaysOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取当前日期是星期几<br>
     *
     * @param date
     * @return 当前日期是星期几
     */
    public static String getWeekOfDate(Date date) {
        String[] weekDays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0)
            w = 0;
        return weekDays[w];
    }

    /**
     * 获取当前日期是星期几<br>
     *
     * @param date
     * @return 当前日期是星期几
     */
    public static Integer getWeekIntOfDate(Date date) {
        Integer[] weekDays = { 0, 1, 2, 3, 4, 5, 6};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0)
            w = 0; // 0 表示星期日
        return weekDays[w];
    }

    /**
     * 判断某个日期是否在两个日期范围之内
     */
    public static boolean theDateInTheScope(String theDate, String scopeStartDate, String scopeEndDate) {
        Date date = parseDate(theDate);
        Date start = parseDate(scopeStartDate);
        Date end = parseDate(scopeEndDate);
        if (date != null && start != null && end != null) {
            return (date.getTime() >= start.getTime() && date.getTime() <= end.getTime());
        }
        return false;
    }

    /**
     * 根据当前时间判断是第几季度
     */
    public static String getTheQuarterOfDate(Date date) {
        int nowMonth = date.getMonth() + 1;
        return String.valueOf((nowMonth + 2) / 3);
    }

    /**
     * 获取今年是哪一年
     */
    public static Integer getNowYear() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(Calendar.YEAR);
    }

    /**
     * 获取本月是哪一月
     */
    public static Integer getNowMonth() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(Calendar.MONTH) + 1;
    }

    /**
     * 获取本月的开始时间
     */
    public static String getBeginDayOfMonth() {
        Calendar cal = Calendar.getInstance();
        cal.set(getNowYear(), getNowMonth() - 1, 1);
        return getStartDateTime(DateUtils.dateToString(cal.getTime()));
    }

    /**
     * 获取本月的结束时间
     */
    public static String getEndDayOfMonth() {
        Calendar cal = Calendar.getInstance();
        int day = cal.getActualMaximum(Calendar.DATE);
        cal.set(getNowYear(), getNowMonth() - 1, day);
        return getEndDateTime(DateUtils.dateToString(cal.getTime()));
    }


    public static void main(String[] args) {
        Calendar now = Calendar.getInstance();
        System.out.println("年: " + now.get(Calendar.YEAR));
        System.out.println("月: " + (now.get(Calendar.MONTH) + 1) + "");
        System.out.println("日: " + now.get(Calendar.DAY_OF_MONTH));

      System.out.println(getEveryday(DateUtils.parseDate("2021-04-02"),new Date()).toString());
    }

}
